#property copyright   "Copyright 2013,mingxinhe@gmail.com"
#property link "mingxinhe@gmail.com"

#define LONG          0
#define SHORT         1
#define ALL           2
#define RETRYCOUNT    10   
#define RETRYDELAY    500

int digitFactor = 1, lotDigits = 1;

extern string CCI_M15_Setting ="------M15 CCI Setting------";
extern int    CCI.M15.Period=13;
extern string CCI.M15.Applied.Price.Desc = "0:PRICE_CLOSE;1:PRICE_OPEN;2:PRICE_HIGH;3:PRICE_LOW";
extern int    CCI.M15.Applied.Price = 0;
extern int    CCI.M15.Shift=1;
extern double CCI.M15.CloseBuy.Level = 0;

extern string CCI_M30_Setting ="------M30 CCI Setting------";
extern bool   CCI_M30_Filter = true;
extern int    CCI.M30.Period=13;
extern string CCI.M30.Applied.Price.Desc = "0:PRICE_CLOSE;1:PRICE_OPEN;2:PRICE_HIGH;3:PRICE_LOW";
extern int    CCI.M30.Applied.Price = 0;
extern int    CCI.M30.Open.Shift=1;
extern int    CCI.M30.Close.Shift=0;
extern double CCI.M30.Buy.Level = 0;
extern double CCI.M30.Sell.Level = -5;
extern double CCI.M30.Span = 5;
extern double CCI.M30.CloseSell.Level = -5;

extern string CCI_H1_Setting ="------H1 CCI Setting------";
extern bool   CCI_H1_Filter = true;
extern int    CCI.H1.Period=13;
extern string CCI.H1.Applied.Price.Desc = "0:PRICE_CLOSE;1:PRICE_OPEN;2:PRICE_HIGH;3:PRICE_LOW";
extern int    CCI.H1.Applied.Price = 0;
extern int    CCI.H1.Open.Shift=1;
extern int    CCI.H1.Close.Shift=0;
extern double CCI.H1.Buy.Level = 0;
extern double CCI.H1.Sell.Level = -5;
extern double CCI.H1.Span = 5;
extern double CCI.H1.CloseSell.Level = -5;

extern string CCI_Day_Setting ="------CCI Setting------";
extern bool   CCI_Day_Filter = false;
extern int    CCI.Day.Period=13;
extern string CCI.Day.Applied.Price.Desc = "0:PRICE_CLOSE;1:PRICE_OPEN;2:PRICE_HIGH;3:PRICE_LOW";
extern int    CCI.Day.Applied.Price = 0;
extern int    CCI.Day.Shift=0;

extern string Money_Management_Setting ="------Money Management Setting------";
extern bool   UseFixedLot = true;
extern double FixedOrderSize = 0.1;
extern double Risk.Percent.Of.Balance = 10;

extern string SLTP_Setting ="------Stop Loss and Take Profit Setting------";
extern double TrailingStopActive.Pips = 150;
extern double TrailingStop.Pips = 100;
extern double TrailingStopStep.Pips = 1;
extern double StopLoss.Pips = 150;
extern double TakeProfit.Pips = 0;

extern string Other_Setting  = "------Other Setting-------";
extern int    MaxTrade = 1;
extern string start.time = "00:00"; 
extern string end.time = "23:59";
extern int    MagicNumber=-1;
extern int    Slippage = 3;

datetime lastM30ActTime, lastH1ActTime;
int orders.total, orders.BUY, orders.SELL, orders.BUYLIMIT, orders.BUYSTOP, orders.SELLLIMIT, orders.SELLSTOP;

double CCI_M30, CCI_H1;

int init()
{    
    if(Bid<10 && Digits==5) { digitFactor=10;}
    if(Bid<10 && Digits==4) { digitFactor= 1;}

    if(Bid>10 && Digits==3) { digitFactor=10;}
    if(Bid>10 && Digits==2) { digitFactor= 1;}   
    
    lotDigits = MathLog(MarketInfo(Symbol(), MODE_LOTSTEP))/MathLog(0.1); 
    StopLoss.Pips *= digitFactor; 
    TakeProfit.Pips *= digitFactor; 
    TrailingStop.Pips *= digitFactor; 
    TrailingStopStep.Pips *= digitFactor; 
    TrailingStopActive.Pips *= digitFactor; 
    
    if (MagicNumber < 0)
    {
        sub_magicnumber();
    }
}

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
{
//----
//----
    return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
{
    double CCI_M15 = iCCI(NULL, PERIOD_M15, CCI.M15.Period, CCI.M15.Applied.Price, CCI.M15.Shift);
    double CCI_M15_Pre = iCCI(NULL, PERIOD_M15, CCI.M15.Period, CCI.M15.Applied.Price, CCI.M15.Shift + 1);
    
    CCI_M30 = iCCI(NULL, PERIOD_M30, CCI.M30.Period, CCI.M30.Applied.Price, CCI.M30.Open.Shift);
    double CCI_M30_Pre = iCCI(NULL, PERIOD_M30, CCI.M30.Period, CCI.M30.Applied.Price, CCI.M30.Open.Shift + 1); 
    
    double CCI_M30_Close = iCCI(NULL, PERIOD_M30, CCI.M30.Period, CCI.M30.Applied.Price, CCI.M30.Close.Shift);   
    
    CCI_H1 = iCCI(NULL, PERIOD_H1, CCI.H1.Period, CCI.H1.Applied.Price, CCI.H1.Open.Shift);           
    double CCI_H1_Pre = iCCI(NULL, PERIOD_H1, CCI.H1.Period, CCI.H1.Applied.Price, CCI.H1.Open.Shift + 1);
    
    double CCI_H1_Close = iCCI(NULL, PERIOD_H1, CCI.H1.Period, CCI.H1.Applied.Price, CCI.H1.Close.Shift); 
    
    double CCI_Day = iCCI(NULL, PERIOD_D1, CCI.Day.Period, CCI.Day.Applied.Price, CCI.Day.Shift);
    
    bool M30LongCondition = CCI_M30_Pre < CCI.M30.Buy.Level && CCI_M30 > CCI.M30.Buy.Level;
    bool H1LongCondition = CCI_H1_Pre < CCI.H1.Buy.Level && CCI_H1 > CCI.H1.Buy.Level;
    
    bool M30ShortCondition = CCI_M30_Pre > CCI.M30.Sell.Level && CCI_M30 < CCI.M30.Sell.Level;
    bool H1ShortCondition = CCI_H1_Pre > CCI.H1.Sell.Level && CCI_H1 < CCI.H1.Sell.Level;
    
    //Print("H1LongCondition:", H1LongCondition, " CCI_H1_Pre:",CCI_H1_Pre, " CCI_H1:",CCI_H1);
    
    bool isTradingTime = isTradingTime();    
    
    if (CCI_M15 < CCI.M15.CloseBuy.Level)
    {
        ExitAll(LONG);
    }    
    else if (isTradingTime && (!CCI_Day_Filter || CCI_Day > 0) && ((M30LongCondition && CCI_M30_Filter && iTime(NULL, PERIOD_M30, 0) > lastM30ActTime) || 
                                         (H1LongCondition && CCI_H1_Filter && iTime(NULL, PERIOD_H1, 0) > lastH1ActTime)))
    {
        CountOrders();
        if (orders.total < MaxTrade)
        {
            if (M30LongCondition && CCI_M30_Filter)
            {
                string CCIStr = "M30" + CCI_M30;
            }
            else if (H1LongCondition && CCI_H1_Filter)
            {
                CCIStr = "H1" + CCI_H1;
            }
            
            if (DoOpenOrder(Symbol(), LONG, getLots(Symbol()), StopLoss.Pips, TakeProfit.Pips, Blue, CCIStr) > 0)
            {
                if (M30LongCondition && CCI_M30_Filter)
                {
                    lastM30ActTime = iTime(NULL, PERIOD_M30, 0);
                }
            
                if (H1LongCondition && CCI_H1_Filter)
                {
                    lastH1ActTime = iTime(NULL, PERIOD_H1, 0);
                }
            }
        }
    }
    
    if ((CCI_M30_Filter && CCI_M30_Close > CCI.M30.CloseSell.Level) || (CCI_H1_Filter && CCI_H1_Close > CCI.H1.CloseSell.Level))
    {
        ExitAll(SHORT);
    }
    else if (isTradingTime && (!CCI_Day_Filter || CCI_Day < 0) && ((M30ShortCondition && CCI_M30_Filter && iTime(NULL, PERIOD_M30, 0) > lastM30ActTime) || 
                                         (H1ShortCondition && CCI_H1_Filter && iTime(NULL, PERIOD_H1, 0) > lastH1ActTime)))
    {
        CountOrders();
        if (orders.total < MaxTrade)
        {
            if (M30ShortCondition && CCI_M30_Filter)
            {
                CCIStr = "M30" + CCI_M30;
            }
            else if (H1ShortCondition && CCI_H1_Filter)
            {
                CCIStr = "H1" + CCI_H1;
            }
            
            if (DoOpenOrder(Symbol(), SHORT, getLots(Symbol()), StopLoss.Pips, TakeProfit.Pips, Red, CCIStr) > 0)
            {
                if (M30ShortCondition && CCI_M30_Filter)
                {
                    lastM30ActTime = iTime(NULL, PERIOD_M30, 0);
                }
            
                if (H1ShortCondition && CCI_H1_Filter)
                {
                    lastH1ActTime = iTime(NULL, PERIOD_H1, 0);
                }
            }
        }
    }            
    
    tailingStopOrders();
}

void tailingStopOrders() 
{            
    if (TrailingStop.Pips <= 0) return;
    if (TrailingStopStep.Pips <= 0) return;
    if (TrailingStopActive.Pips <= 0) return;
    
    for (int i = OrdersTotal() - 1; i >= 0; i--) 
    {
      if (!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;             
      if(OrderMagicNumber() == MagicNumber)
      {
         string symbolName = OrderSymbol();
         double dDigits = MarketInfo(symbolName, MODE_DIGITS);
         double dPoint = MarketInfo(symbolName, MODE_POINT);   

         double dAsk = MarketInfo(symbolName, MODE_ASK);
         double dBid = MarketInfo(symbolName, MODE_BID);
             
         if (OrderType() == OP_BUY  && TrailingStop.Pips > 0) 
         {       
            double SL = dBid - TrailingStop.Pips*dPoint;            
            if (dBid-OrderOpenPrice()>=TrailingStopActive.Pips*dPoint && SL >= OrderStopLoss() + TrailingStopStep.Pips*dPoint) 
            {                 
                modifyOrderByPrice(OrderTicket(), OrderOpenPrice(), SL, OrderTakeProfit());
            }
         }

         if (OrderType() == OP_SELL  && TrailingStop.Pips > 0) 
         {                
            SL = dAsk + TrailingStop.Pips*dPoint;
            if (OrderOpenPrice()-dAsk>=TrailingStopActive.Pips*dPoint && (SL <= OrderStopLoss() - TrailingStopStep.Pips*dPoint|| OrderStopLoss() == 0)) 
            {               
                modifyOrderByPrice(OrderTicket(), OrderOpenPrice(), SL, OrderTakeProfit());
            }
         }
      }
   }
}

//  Magic Number - calculated from a sum of account number and ASCII-codes from currency pair                                                                           
int sub_magicnumber()
{
     string local_currpair = Symbol();
     int local_length = StringLen (local_currpair);
     int local_asciisum = 0;
     int local_counter;

     for (local_counter = 0; local_counter < local_length -1; local_counter++)
        local_asciisum += StringGetChar (local_currpair, local_counter);
     MagicNumber = AccountNumber() + local_asciisum;   
}

//Count Orders and calculate the group's average entry point & spread
int CountOrders() 
{
   orders.BUY = 0;
   orders.SELL = 0;
   orders.BUYLIMIT = 0;
   orders.BUYSTOP = 0;
   orders.SELLLIMIT = 0;
   orders.SELLSTOP = 0;
   
   for( int i = OrdersTotal() - 1; i >= 0; i--) 
   {   
      if (!OrderSelect( i, SELECT_BY_POS)) continue;
      
      if( OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber ) 
      {                       
         if( OrderType() == OP_BUY ) 
         { 
             orders.BUY++; 
         }
         if( OrderType() == OP_SELL ) 
         { 
             orders.SELL++; 
         }
         if( OrderType() == OP_BUYLIMIT ) 
         { 
             orders.BUYLIMIT++; 
         }
         if( OrderType() == OP_BUYSTOP ) 
         { 
             orders.BUYSTOP++; 
         }
         if( OrderType() == OP_SELLLIMIT ) 
         { 
             orders.SELLLIMIT++; 
         }
         if( OrderType() == OP_SELLSTOP ) 
         { 
             orders.SELLSTOP++; 
         }
      }
   }
   
   orders.total = orders.BUY + orders.SELL;
   
   return(orders.total);

}

//close an order with specifed ticket, if failed try again with RETRYCOUNT times
bool Exit(int ticket, string symbolName, int dir, double volume, color clr)  {
    int i, j, cmd;
    double prc, sl, tp;
    string cmt;

    bool closed;

    Print("Exit("+dir+","+DoubleToStr(volume,3)+")");

    for (i=0; i<RETRYCOUNT; i++) {
        for (j=0; (j<50) && IsTradeContextBusy(); j++)
            Sleep(100);
        RefreshRates();

        if (dir == OP_BUY) {
            prc = MarketInfo(symbolName, MODE_BID);
        }
        if (dir == OP_SELL) {
            prc = MarketInfo(symbolName, MODE_ASK);
       }
        Print("Exit: prc="+DoubleToStr(prc,MarketInfo(symbolName, MODE_DIGITS)));

        closed = OrderClose(ticket,volume,prc,Slippage,clr);
        if (closed) {
            Print("Trade closed");

            return (true);
        }

        Print("Exit: error \'"+ErrorDescription(GetLastError())+"\' when exiting with "+DoubleToStr(volume,3)+" @"+DoubleToStr(prc,MarketInfo(symbolName, MODE_DIGITS)));
        Sleep(RETRYDELAY);
    }

    Print("Exit: can\'t enter after "+RETRYCOUNT+" retries");
    return (false);
}

double getLots(string symbolName)
{
    int lotDigits = MathLog(MarketInfo(symbolName, MODE_LOTSTEP))/MathLog(0.1); 
    if (UseFixedLot)
    {
        double lot = FixedOrderSize;
    }
    else
    {        
        lot = AccountBalance()*Risk.Percent.Of.Balance/100/MarketInfo(symbolName, MODE_MARGINREQUIRED);
    }
    
    if (lot < MarketInfo(symbolName, MODE_MINLOT))
    {
        Print("The lot is too small hence the minimum allowed lot is used.");
    }
    
    if (lot > MarketInfo(symbolName, MODE_MAXLOT))
    {
        Print("The lot is too big hence the maximum allowed lot is used.");
    }
    
    return (NormalizeDouble(lot, lotDigits));
}

//open an order, if failed try again with RETRYCOUNT times
int DoOpenOrder(string symbolName, int dir, double volume, int stop, int take, color clr, string comment = "")  {
 
   Print("comment:",comment);

   double sl, tp, entryPrice;

   int ticket = 0;   

   double lots = volume;
   string info;   
   
   for (int i=0; i<RETRYCOUNT; i++) {
     for (int j=0; (j<50) && IsTradeContextBusy(); j++)
         Sleep(100);
      RefreshRates();   
      
      double dAsk = MarketInfo(symbolName, MODE_ASK);
      double dBid = MarketInfo(symbolName, MODE_BID);
      double dPoint = MarketInfo(symbolName, MODE_POINT);
      double dDigits = MarketInfo(symbolName, MODE_DIGITS);


      switch(dir)  {
         case LONG:               
               entryPrice = NormalizeDouble(dAsk, dDigits);
               
               if (stop != 0) { sl = entryPrice-(stop*dPoint); }
                else { sl = 0; }
                if (take != 0) { tp = entryPrice +(take*dPoint); }
                else { tp = 0; }
                
                
                info = "Type: " + dir + ", \nentryPrice: " + DoubleToStr(entryPrice, dDigits) 
                   + ", \nLots " + DoubleToStr(lots, 2) + " , \nStop: " + DoubleToStr(sl, dDigits)  
                   + ", \nTP: " + DoubleToStr(tp, dDigits);
                Print(info);
                Comment(info);                
               
                ticket = OrderSend(symbolName, OP_BUY, lots, entryPrice, Slippage, sl, tp, comment, MagicNumber, 0, clr);
                if (ticket < 0)  
                {
                    ticket = OrderSend(symbolName, OP_BUY, lots, entryPrice, Slippage, 0, 0, comment, MagicNumber, 0, clr);                    
                }
                if (ticket > 0)  
                {
                     if(OrderSelect(ticket, SELECT_BY_TICKET))
                     {
                         modifyOrderByPrice(ticket, OrderOpenPrice(), sl, tp);
                     }
                }
                
                break;

         case SHORT:
              entryPrice = NormalizeDouble(dBid, dDigits);
              if (stop != 0) { sl = entryPrice+(stop*dPoint); }
                else { sl = 0; }
                if (take != 0) { tp = entryPrice-(take*dPoint); }
                else { tp = 0; }
                
                info = "Type: " + dir + ", \nentryPrice: " + DoubleToStr(entryPrice, dDigits)
                   + ", \nLots " + DoubleToStr(lots, 2) + " , \nStop: " + DoubleToStr(sl, dDigits)  
                   + ", \nTP: " + DoubleToStr(tp, dDigits);
              Print(info);
              Comment(info);
          
                ticket = OrderSend(symbolName, OP_SELL, lots, entryPrice, Slippage, sl, tp, comment, MagicNumber, 0, clr);     
                if (ticket < 0)  
                {
                    ticket = OrderSend(symbolName, OP_SELL, lots, entryPrice, Slippage, 0, 0, comment, MagicNumber, 0, clr);                    
                    
                }   
                if (ticket > 0)  
                {
                   if(OrderSelect(ticket, SELECT_BY_TICKET))
                   {
                       modifyOrderByPrice(ticket, OrderOpenPrice(), sl, tp);
                   }
                }                      
                break;
      }
           
      if( ticket > 0 ) { return( ticket ); }
      else {
         Print("DoOpenOrder: error \'"+ErrorDescription(GetLastError())+"\' when opening entry order");
         Sleep(RETRYDELAY);      
      }
      
   }
      
   return( false );
}

//modify an order with specified ticket, if failed try again with RETRYCOUNT times
bool modifyOrderByPrice(int ticket, double price, double stopLoss, double takeProfit)  
{
   bool retVal = true;     
   
   if(!OrderSelect(ticket, SELECT_BY_TICKET)) return (false);
   
   for (int i=0; i<RETRYCOUNT; i++) 
   {
     for (int j=0; (j<50) && IsTradeContextBusy(); j++)
        Sleep(100);
      RefreshRates();                        

       if (MathAbs(OrderStopLoss() - stopLoss) > Point || MathAbs(OrderTakeProfit() - takeProfit) > Point)
       {              
           retVal = OrderModify(ticket, price, stopLoss, takeProfit, 0);
       }
         
      if(retVal) { return( true ); } 
      else {
         Print("DoModifyOrder: error \'"+ErrorDescription(GetLastError())+"\' when modifying order SL:", stopLoss, " TP:", takeProfit, " OrderOpenPrice:",OrderOpenPrice(), " OrderStopLoss:",OrderStopLoss());
         Sleep(RETRYDELAY);      
      }  
   }      
   return( false );
}

//close all open positions with the specified LONG or SHORT direction
void ExitAll(int direction) {       

   int i;
   
   CountOrders(); 
   if( orders.SELL != 0 && direction == SHORT) 
   {      
         for(i = OrdersTotal() - 1; i >= 0; i--) 
         {
            if (!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;       
            if( OrderMagicNumber() == MagicNumber && OrderSymbol() == Symbol() ) 
            {              
                if (StringFind(OrderComment(), "M30") == 0)
                {
                    double old_CCI = StrToDouble(StringSubstr(OrderComment(), 3));
                    if (MathAbs(CCI_M30 - old_CCI) < CCI.M30.Span)
                    {
                        Print("old_CCI:",old_CCI, " CCI_M30:",CCI_M30);
                        continue;
                    }              
                }
                if (StringFind(OrderComment(), "H1") == 0)
                {
                    old_CCI = StrToDouble(StringSubstr(OrderComment(), 2)); 
                    if (MathAbs(CCI_H1 - old_CCI) < CCI.H1.Span)
                    {
                        Print("old_CCI:",old_CCI, " CCI_H1:",CCI_H1);
                        continue;
                    }               
                }
                if (OrderType() == OP_SELL) { Exit( OrderTicket(), Symbol(), OP_SELL, OrderLots(), Red); }
            }
         }          
     
      return( true );
   }
   
   if( orders.BUY != 0 && direction == LONG) 
   {  
         for(i = OrdersTotal() - 1; i >= 0; i--) 
         {         
            if (!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
            if( OrderMagicNumber() == MagicNumber && OrderSymbol() == Symbol()) {  
                if (StringFind(OrderComment(), "M30") == 0)
                {
                    old_CCI = StrToDouble(StringSubstr(OrderComment(), 3));
                    if (MathAbs(CCI_M30 - old_CCI) < CCI.M30.Span)
                    {
                        Print("old_CCI:",old_CCI, " CCI_M30:",CCI_M30);
                        continue;
                    }              
                }
                if (StringFind(OrderComment(), "H1") == 0)
                {
                    old_CCI = StrToDouble(StringSubstr(OrderComment(), 2)); 
                    if (MathAbs(CCI_H1 - old_CCI) < CCI.H1.Span)
                    {
                        Print("old_CCI:",old_CCI, " CCI_H1:",CCI_H1);
                        continue;
                    }               
                }        
                if (OrderType() == OP_BUY) { Exit(OrderTicket(), Symbol(), OP_BUY, OrderLots(), Blue); }
            }
         } 
               
      return( true );
   }   
}

bool isTradingTime()
{
   bool isTT = false;

   datetime tm0 = TimeCurrent();
   datetime tm1, tm2;

   tm1 = StrToTime(TimeToStr(tm0, TIME_DATE) + " " + start.time);
   tm2 = StrToTime(TimeToStr(tm0, TIME_DATE) + " " + end.time);

   if (tm1 <= tm2) 
     isTT = tm1 <= tm0 && tm0 <= tm2;

   return (isTT);
}

//return error message for each kind of errorCode
string ErrorDescription(int error_code)
{
    string error_string;

    switch( error_code ) {
        case 0:
        case 1:   error_string="no error";                                                  break;
        case 2:   error_string="common error";                                              break;
        case 3:   error_string="invalid trade parameters";                                  break;
        case 4:   error_string="trade server is busy";                                      break;
        case 5:   error_string="old version of the client terminal";                        break;
        case 6:   error_string="no connection with trade server";                           break;
        case 7:   error_string="not enough rights";                                         break;
        case 8:   error_string="too frequent requests";                                     break;
        case 9:   error_string="malfunctional trade operation (never returned error)";      break;
        case 64:  error_string="account disabled";                                          break;
        case 65:  error_string="invalid account";                                           break;
        case 128: error_string="trade timeout";                                             break;
        case 129: error_string="invalid price";                                             break;
        case 130: error_string="invalid stops";                                             break;
        case 131: error_string="invalid trade volume";                                      break;
        case 132: error_string="market is closed";                                          break;
        case 133: error_string="trade is disabled";                                         break;
        case 134: error_string="not enough money";                                          break;
        case 135: error_string="price changed";                                             break;
        case 136: error_string="off quotes";                                                break;
        case 137: error_string="broker is busy (never returned error)";                     break;
        case 138: error_string="requote";                                                   break;
        case 139: error_string="order is locked";                                           break;
        case 140: error_string="long positions only allowed";                               break;
        case 141: error_string="too many requests";                                         break;
        case 145: error_string="modification denied because order too close to market";     break;
        case 146: error_string="trade context is busy";                                     break;
        case 147: error_string="expirations are denied by broker";                          break;
        case 148: error_string="amount of open and pending orders has reached the limit";   break;
        case 149: error_string="hedging is prohibited";                                     break;
        case 150: error_string="prohibited by FIFO rules";                                  break;
        case 4000: error_string="no error (never generated code)";                          break;
        case 4001: error_string="wrong function pointer";                                   break;
        case 4002: error_string="array index is out of range";                              break;
        case 4003: error_string="no memory for function call stack";                        break;
        case 4004: error_string="recursive stack overflow";                                 break;
        case 4005: error_string="not enough stack for parameter";                           break;
        case 4006: error_string="no memory for parameter string";                           break;
        case 4007: error_string="no memory for temp string";                                break;
        case 4008: error_string="not initialized string";                                   break;
        case 4009: error_string="not initialized string in array";                          break;
        case 4010: error_string="no memory for array\' string";                             break;
        case 4011: error_string="too long string";                                          break;
        case 4012: error_string="remainder from zero divide";                               break;
        case 4013: error_string="zero divide";                                              break;
        case 4014: error_string="unknown command";                                          break;
        case 4015: error_string="wrong jump (never generated error)";                       break;
        case 4016: error_string="not initialized array";                                    break;
        case 4017: error_string="dll calls are not allowed";                                break;
        case 4018: error_string="cannot load library";                                      break;
        case 4019: error_string="cannot call function";                                     break;
        case 4020: error_string="expert function calls are not allowed";                    break;
        case 4021: error_string="not enough memory for temp string returned from function"; break;
        case 4022: error_string="system is busy (never generated error)";                   break;
        case 4050: error_string="invalid function parameters count";                        break;
        case 4051: error_string="invalid function parameter value";                         break;
        case 4052: error_string="string function internal error";                           break;
        case 4053: error_string="some array error";                                         break;
        case 4054: error_string="incorrect series array using";                             break;
        case 4055: error_string="custom indicator error";                                   break;
        case 4056: error_string="arrays are incompatible";                                  break;
        case 4057: error_string="global variables processing error";                        break;
        case 4058: error_string="global variable not found";                                break;
        case 4059: error_string="function is not allowed in testing mode";                  break;
        case 4060: error_string="function is not confirmed";                                break;
        case 4061: error_string="send mail error";                                          break;
        case 4062: error_string="string parameter expected";                                break;
        case 4063: error_string="integer parameter expected";                               break;
        case 4064: error_string="double parameter expected";                                break;
        case 4065: error_string="array as parameter expected";                              break;
        case 4066: error_string="requested history data in update state";                   break;
        case 4099: error_string="end of file";                                              break;
        case 4100: error_string="some file error";                                          break;
        case 4101: error_string="wrong file name";                                          break;
        case 4102: error_string="too many opened files";                                    break;
        case 4103: error_string="cannot open file";                                         break;
        case 4104: error_string="incompatible access to a file";                            break;
        case 4105: error_string="no order selected";                                        break;
        case 4106: error_string="unknown symbol";                                           break;
        case 4107: error_string="invalid price parameter for trade function";               break;
        case 4108: error_string="invalid ticket";                                           break;
        case 4109: error_string="trade is not allowed in the expert properties";            break;
        case 4110: error_string="longs are not allowed in the expert properties";           break;
        case 4111: error_string="shorts are not allowed in the expert properties";          break;
        case 4200: error_string="object is already exist";                                  break;
        case 4201: error_string="unknown object property";                                  break;
        case 4202: error_string="object is not exist";                                      break;
        case 4203: error_string="unknown object type";                                      break;
        case 4204: error_string="no object name";                                           break;
        case 4205: error_string="object coordinates error";                                 break;
        case 4206: error_string="no specified subwindow";                                   break;
        default:   error_string="unknown error";
    }

    return(error_string);
}

